home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 2 / Amiga Tools 2.iso / tools / packer / tar / src / create.c < prev    next >
C/C++ Source or Header  |  1995-03-09  |  16KB  |  679 lines

  1. /*
  2.  * Create a tar archive.
  3.  *
  4.  * Written 25 Aug 1985 by John Gilmore, ihnp4!hoptoad!gnu.
  5.  *
  6.  * @(#)create.c 1.36 11/6/87 Public Domain - gnu
  7.  */
  8. #include <sys/types.h>
  9. #include <sys/stat.h>
  10. #include <stdio.h>
  11.  
  12. #ifndef V7
  13. #include <fcntl.h>
  14. #endif
  15.  
  16. #if !defined(MSDOS) && !defined(AMIGA)
  17. #include <pwd.h>
  18. #include <grp.h>
  19. #endif
  20.  
  21. #ifdef BSD42
  22. #include <sys/dir.h>
  23. #else
  24. #ifdef MSDOS
  25. #include <sys/dir.h>
  26. #else
  27. #ifdef AMIGA
  28. #include <dirent.h>
  29. #else
  30. /*
  31.  * FIXME: On other systems there is no standard place for the header file
  32.  * for the portable directory access routines.  Change the #include line
  33.  * below to bring it in from wherever it is.
  34.  */
  35. #include "ndir.h"
  36. #endif
  37. #endif
  38. #endif
  39.  
  40. #ifdef USG
  41. #include <sys/sysmacros.h>    /* major() and minor() defined here */
  42. #endif
  43.  
  44. /*
  45.  * V7 doesn't have a #define for this.
  46.  */
  47. #ifndef O_RDONLY
  48. #define    O_RDONLY    0
  49. #endif
  50.  
  51. /*
  52.  * Most people don't have a #define for this.
  53.  */
  54. #ifndef    O_BINARY
  55. #define    O_BINARY    0
  56. #endif
  57.  
  58. #include "tar.h"
  59. #include "port.h"
  60.  
  61. extern union record *head;        /* Points to current tape header */
  62. extern struct stat hstat;        /* Stat struct corresponding */
  63. extern int head_standard;        /* Tape header is in ANSI format */
  64.  
  65. /*
  66.  * If there are no symbolic links, there is no lstat().  Use stat().
  67.  */
  68. #ifndef S_IFLNK
  69. #define lstat stat
  70. #endif
  71.  
  72. extern char    *malloc();
  73. extern char    *strcpy();
  74. extern char    *strncpy();
  75. extern void    bzero();
  76. extern void    bcopy();
  77. extern int    errno;
  78.  
  79. extern void print_header();
  80.  
  81. union record *start_header();
  82. void finish_header();
  83. void finduname();
  84. void findgname();
  85. char *name_next();
  86. void to_oct(), to_hex();
  87. void dump_file();
  88.  
  89. static nolinks;            /* Gets set if we run out of RAM */
  90.  
  91. void
  92. create_archive()
  93. {
  94.     register char    *p;
  95.  
  96.     open_archive(0);        /* Open for writing */
  97.  
  98.     while (p = name_next()) {
  99. #ifdef AMIGA
  100.         if (!strcmp(p, "."))    /* convert . and ./ to "" */
  101.             p++;
  102.         else if (!strcmp(p, "./"))
  103.             p += 2;
  104. #endif
  105.         dump_file(p, -1);
  106.     }
  107.  
  108.     write_eot();
  109.     close_archive();
  110.     name_close();
  111. }        
  112.  
  113. /*
  114.  * Dump a single file.  If it's a directory, recurse.
  115.  * Result is 1 for success, 0 for failure.
  116.  * Sets global "hstat" to stat() output for this file.
  117.  */
  118. void
  119. dump_file(p, curdev)
  120.     char    *p;            /* File name to dump */
  121.     int    curdev;            /* Device our parent dir was on */
  122. {
  123.     union record    *header;
  124.     char type;
  125.  
  126.     /*
  127.      * Use stat if following (rather than dumping) 4.2BSD's
  128.      * symbolic links.  Otherwise, use lstat (which, on non-4.2
  129.      * systems, is #define'd to stat anyway.
  130.      */
  131.     if (0 != f_follow_links? stat(p, &hstat): lstat(p, &hstat))
  132.     {
  133. badperror:
  134.         perror(p);
  135. badfile:
  136.         errors++;
  137.         return;
  138.     }
  139.  
  140.     /*
  141.      * See if we are crossing from one file system to another,
  142.      * and avoid doing so if the user only wants to dump one file system.
  143.      */
  144.     if (f_local_filesys && curdev >= 0 && curdev != hstat.st_dev) {
  145.         annorec(stderr, tar);
  146.         fprintf(stderr,
  147.             "%s: is on a different filesystem; not dumped\n",
  148.             p);
  149.         return;
  150.     }
  151. #ifdef AMIGA
  152.     /*
  153.      * If f_archive_check is set, check the archived bit of the
  154.      * file and don't archive it if the bit is set and it's a normal
  155.        * file.
  156.      */
  157.     if (f_archive_check && (hstat.st_prot & FIBF_ARCHIVE) &&
  158.         !(hstat.st_mode & S_IFDIR))
  159.     {
  160.         if (f_verbose > 1)
  161.         {
  162.         annorec(stderr, tar);
  163.         fprintf(stderr, "%s: archive bit set, not dumping\n", p);
  164.         }
  165.         return;
  166.     }    
  167. #endif
  168.  
  169.     /*
  170.      * Check for multiple links.
  171.      *
  172.      * We maintain a list of all such files that we've written so
  173.      * far.  Any time we see another, we check the list and
  174.      * avoid dumping the data again if we've done it once already.
  175.      */
  176.     if (hstat.st_nlink > 1) switch (hstat.st_mode & S_IFMT) {
  177.         register struct link    *lp;
  178.  
  179.     case S_IFREG:            /* Regular file */
  180. #ifdef S_IFCTG
  181.     case S_IFCTG:            /* Contigous file */
  182. #endif
  183. #ifdef S_IFCHR
  184.     case S_IFCHR:            /* Character special file */
  185. #endif
  186.  
  187. #ifdef S_IFBLK
  188.     case S_IFBLK:            /* Block     special file */
  189. #endif
  190.  
  191. #ifdef S_IFIFO
  192.     case S_IFIFO:            /* Fifo      special file */
  193. #endif
  194.  
  195.         /* First quick and dirty.  Hashing, etc later FIXME */
  196.         for (lp = linklist; lp; lp = lp->next) {
  197.             if (lp->ino == hstat.st_ino &&
  198.                 lp->dev == hstat.st_dev) {
  199.                 /* We found a link. */
  200.                 hstat.st_size = 0;
  201.                 header = start_header(p, &hstat);
  202.                 if (header == NULL) goto badfile;
  203.                 strcpy(header->header.linkname,
  204.                     lp->name);
  205.                 header->header.linkflag = LF_LINK;
  206.                 finish_header(header);
  207.         /* FIXME: Maybe remove from list after all links found? */
  208.                 return;        /* We dumped it */
  209.             }
  210.         }
  211.  
  212.         /* Not found.  Add it to the list of possible links. */
  213.         lp = (struct link *) malloc( (unsigned)
  214.             (strlen(p) + sizeof(struct link) - NAMSIZ));
  215.         if (!lp) {
  216.             if (!nolinks) {
  217.                 fprintf(stderr,
  218.     "tar: no memory for links, they will be dumped as separate files\n");
  219.                 nolinks++;
  220.             }
  221.         }
  222.         lp->ino = hstat.st_ino;
  223.         lp->dev = hstat.st_dev;
  224.         strcpy(lp->name, p);
  225.         lp->next = linklist;
  226.         linklist = lp;
  227.     }
  228.  
  229.     /*
  230.      * This is not a link to a previously dumped file, so dump it.
  231.      */
  232.     switch (hstat.st_mode & S_IFMT) {
  233.  
  234.     case S_IFREG:            /* Regular file */
  235. #ifdef S_IFCTG
  236.     case S_IFCTG:            /* Contigous file */
  237. #endif
  238.     {
  239.         int    f;        /* File descriptor */
  240.         int    bufsize, count;
  241.         register long    sizeleft;
  242.         register union record     *start;
  243.  
  244.         sizeleft = hstat.st_size;
  245.         /* Don't bother opening empty, world readable files. */
  246.         if (sizeleft > 0 || 0444 != (0444 & hstat.st_mode)) {
  247.             f = open(p, O_RDONLY|O_BINARY);
  248.             if (f < 0) goto badperror;
  249.         } else {
  250.             f = -1;
  251.         }
  252.         header = start_header(p, &hstat);
  253.         if (header == NULL) goto badfile;
  254. #ifdef S_IFCTG
  255.         /* Mark contiguous files, if we support them */
  256.         if (f_standard && (hstat.st_mode & S_IFMT) == S_IFCTG) {
  257.             header->header.linkflag = LF_CONTIG;
  258.         }
  259. #endif
  260.         finish_header(header);
  261.         while (sizeleft > 0) {
  262.             start = findrec();
  263.             bufsize = endofrecs()->charptr - start->charptr;
  264.             if (sizeleft < bufsize) {
  265.                 /* Last read -- zero out area beyond */
  266.                 bufsize = (int)sizeleft;
  267.                 count = bufsize % RECORDSIZE;
  268.                 if (count) 
  269.                     bzero(start->charptr + sizeleft,
  270.                         RECORDSIZE - count);
  271.             }
  272.             count = read(f, start->charptr, bufsize);
  273.             if (count < 0) {
  274.                 annorec(stderr, tar);
  275.                 fprintf(stderr,
  276.                   "read error at byte %ld, reading %d bytes, in file ",
  277.                     hstat.st_size - sizeleft,
  278.                     bufsize);
  279.                 perror(p);    /* FIXME */
  280.                 goto padit;
  281.             }
  282.             sizeleft -= count;
  283.             /* This is nonportable (the type of userec's arg). */
  284.             userec(start+(count-1)/RECORDSIZE);
  285.             if (count == bufsize) continue;
  286.             annorec(stderr, tar);
  287.             fprintf(stderr,
  288.               "%s: file shrunk by %d bytes, padding with zeros.\n",
  289.                 p, sizeleft);
  290.             goto padit;        /* Short read */
  291.         }
  292.         if (f >= 0)
  293.             (void)close(f);
  294. #ifdef AMIGA
  295.         if (f_archive_set)
  296.         {
  297.             if (SmartSetProtection(p, hstat.st_prot | 
  298.             FIBF_ARCHIVE) < 0)
  299.             {
  300.                 fputs("tar: Error setting archive bit on ", stderr);
  301.             perror(p);
  302.             }
  303.         }
  304. #endif        
  305.         break;
  306.  
  307.         /*
  308.          * File shrunk or gave error, pad out tape to match
  309.          * the size we specified in the header.
  310.          */
  311.     padit:
  312.         abort();
  313.     }
  314.  
  315. #ifdef S_IFLNK
  316.     case S_IFLNK:            /* Symbolic link */
  317.     {
  318.         int size;
  319.  
  320.         hstat.st_size = 0;        /* Force 0 size on symlink */
  321.         header = start_header(p, &hstat);
  322.         if (header == NULL) goto badfile;
  323.         size = readlink(p, header->header.linkname, NAMSIZ);
  324.         if (size < 0) goto badperror;
  325.         if (size == NAMSIZ) {
  326.             annorec(stderr, tar);
  327.             fprintf(stderr,
  328.                 "%s: symbolic link too long\n", p);
  329.             break;
  330.         }
  331.         header->header.linkname[size] = '\0';
  332.         header->header.linkflag = LF_SYMLINK;
  333.         finish_header(header);        /* Nothing more to do to it */
  334.     }
  335.         break;
  336. #endif
  337.  
  338.     case S_IFDIR:            /* Directory */
  339.     {
  340.         register DIR *dirp;
  341.         register struct dirent *d;
  342.         char namebuf[NAMSIZ+2];
  343.         register int len;
  344.         int our_device = hstat.st_dev;
  345.  
  346.         /* Build new prototype name */
  347.         strncpy(namebuf, p, sizeof (namebuf));
  348. #ifdef AMIGA
  349.         /*
  350.          * If user types "" (current dir), make namebuf be ./ - this
  351.          * will later be stripped.
  352.          */
  353.         if (!*namebuf) {
  354.             strcpy(namebuf, "./");
  355.         }
  356. #endif
  357.         len = strlen(namebuf);
  358.         while (len >= 1 && '/' == namebuf[len-1]) 
  359.             len--;            /* Delete trailing slashes */
  360. #ifdef AMIGA
  361.         if (namebuf[len - 1] != ':')     /* no / after : */
  362.             namebuf[len++] = '/';    /* Now add exactly one back */
  363. #else
  364.         namebuf[len++] = '/';        /* Now add exactly one back */
  365. #endif
  366.         namebuf[len] = '\0';        /* Make sure null-terminated */
  367.         /*
  368.          * Output directory header record with permissions
  369.          * FIXME, do this AFTER files, to avoid R/O dir problems?
  370.          * If old archive format, don't write record at all.
  371.          */
  372.         if (!f_oldarch) {
  373.             hstat.st_size = 0;    /* Force 0 size on dir */
  374.             /*
  375.              * If people could really read standard archives,
  376.              * this should be:        (FIXME)
  377.             header = start_header(f_standard? p: namebuf, &hstat);
  378.              * but since they'd interpret LF_DIR records as
  379.              * regular files, we'd better put the / on the name.
  380.              */
  381.             header = start_header(namebuf, &hstat);
  382.             if (header == NULL)
  383.                 goto badfile;    /* eg name too long */
  384.             if (f_standard) {
  385.                 header->header.linkflag = LF_DIR;
  386.             }
  387.             finish_header(header);    /* Done with directory header */
  388.         }
  389.  
  390.         /* Hack to remove "./" from the front of all the file names */
  391.         if (len == 2 && namebuf[0] == '.') {
  392.             len = 0;
  393.         }
  394.  
  395.         /* Now output all the files in the directory */
  396.         if (f_dironly)
  397.             break;        /* Unless the user says no */
  398.         errno = 0;
  399.         dirp = opendir(p);
  400.         if (!dirp) {
  401.             if (errno) {
  402.                 perror (p);
  403.             } else {
  404.                 annorec(stderr, tar);
  405.                 fprintf(stderr, "%s: error opening directory",
  406.                     p);
  407.             }
  408.             break;
  409.         }
  410.         
  411.         /* Should speed this up by cd-ing into the dir, FIXME */
  412.         while (NULL != (d=readdir(dirp))) {
  413.             /* Skip . and .. */
  414.             if (d->d_name[0] == '.') {
  415.                 if (d->d_name[1] == '\0') continue;
  416.                 if (d->d_name[1] == '.') {
  417.                     if (d->d_name[2] == '\0') continue;
  418.                 }
  419.             }
  420.             if (strlen(d->d_name) + len >= NAMSIZ) {
  421.                 annorec(stderr, tar);
  422.                 fprintf(stderr, "%s%s: name too long\n", 
  423.                     namebuf, d->d_name);
  424.                 continue;
  425.             }
  426.             strcpy(namebuf+len, d->d_name);
  427.             dump_file(namebuf, our_device);
  428.         }
  429.  
  430.         closedir(dirp);
  431. #ifdef AMIGA
  432.         if (f_archive_set)
  433.         {
  434.             if (SmartSetProtection(p, hstat.st_prot | 
  435.             FIBF_ARCHIVE) < 0)
  436.             {
  437.                 fputs("tar: Error setting archive bit on ", stderr);
  438.             perror(p);
  439.             }
  440.         }
  441. #endif
  442.     }
  443.         break;
  444.  
  445. #ifdef S_IFCHR
  446.     case S_IFCHR:            /* Character special file */
  447.         type = LF_CHR;
  448.         goto easy;
  449. #endif
  450.  
  451. #ifdef S_IFBLK
  452.     case S_IFBLK:            /* Block     special file */
  453.         type = LF_BLK;
  454.         goto easy;
  455. #endif
  456.  
  457. #ifdef S_IFIFO
  458.     case S_IFIFO:            /* Fifo      special file */
  459.         type = LF_FIFO;
  460. #endif
  461.  
  462.     easy:
  463.         if (!f_standard) goto unknown;
  464.  
  465.         hstat.st_size = 0;        /* Force 0 size */
  466.         header = start_header(p, &hstat);
  467.         if (header == NULL) goto badfile;    /* eg name too long */
  468.  
  469.         header->header.linkflag = type;
  470.         if (type != LF_FIFO) {
  471.             to_oct((long) major(hstat.st_rdev), 8,
  472.                 header->header.devmajor);
  473.             to_oct((long) minor(hstat.st_rdev), 8,
  474.                 header->header.devminor);
  475.         }
  476.  
  477.         finish_header(header);
  478.         break;
  479.  
  480.     default:
  481.     unknown:
  482.         annorec(stderr, tar);
  483.         fprintf(stderr,
  484.             "%s: Unknown file type; file ignored.\n", p);
  485.         break;
  486.     }
  487. }
  488.  
  489.  
  490. /*
  491.  * Make a header block for the file  name  whose stat info is  st .
  492.  * Return header pointer for success, NULL if the name is too long.
  493.  */
  494. union record *
  495. start_header(name, st)
  496.     char    *name;
  497.     register struct stat *st;
  498. {
  499.     register union record *header;
  500.     char newname[NAMSIZ+2];
  501.     header = (union record *) findrec();
  502.     bzero(header->charptr, sizeof(*header)); /* XXX speed up */
  503.  
  504.     /*
  505.      * Check the file name and put it in the record.
  506.      */
  507. #ifdef AMIGA
  508.     cvtAmi2UNIX(name, newname);
  509.     name = newname;    /* point name at newname, but leave orig string alone */
  510. #else
  511.     while ('/' == *name) {
  512.         static int warned_once = 0;
  513.  
  514.         name++;                /* Force relative path */
  515.         if (!warned_once++) {
  516.             annorec(stderr, tar);
  517.             fprintf(stderr,
  518.     "Removing leading / from absolute path names in the archive.\n");
  519.         }
  520.     }
  521. #endif
  522.     strcpy(header->header.name, name);
  523.     if (header->header.name[NAMSIZ-1]) {
  524.         annorec(stderr, tar);
  525.         fprintf(stderr, "%s: name too long\n", name);
  526.         return NULL;
  527.     }
  528.  
  529.     to_oct((long) (st->st_mode & ~S_IFMT),
  530.                     8,  header->header.mode);
  531.     to_oct((long) st->st_uid,    8,  header->header.uid);
  532.     to_oct((long) st->st_gid,    8,  header->header.gid);
  533.     to_oct((long) st->st_size,    1+12, header->header.size);
  534.     to_oct((long) st->st_mtime,    1+12, header->header.mtime);
  535.     /* header->header.linkflag is left as null */
  536. #ifdef AMIGA
  537.     strcpy(header->header.magic_cookie, "AmigaTar");
  538.     to_hex(st->st_prot, header->header.amiga_modes);
  539.     memset(header->header.comment, '\0', sizeof(header->header.comment));
  540.     strcpy(header->header.comment, st->st_comment);
  541.     to_hex(st->st_date.ds_Days, header->header.ds_Days);
  542.     to_hex(st->st_date.ds_Minute, header->header.ds_Minute);
  543.     to_hex(st->st_date.ds_Tick, header->header.ds_Tick);
  544. #endif
  545. #ifndef NONAMES
  546.     /* Fill in new Unix Standard fields if desired. */
  547.     if (f_standard) {
  548.         header->header.linkflag = LF_NORMAL;    /* New default */
  549.         strcpy(header->header.magic, TMAGIC);    /* Mark as Unix Std */
  550.         finduname(header->header.uname, st->st_uid);
  551.         findgname(header->header.gname, st->st_gid);
  552.     }
  553. #endif
  554.     return header;
  555. }
  556.  
  557. /* 
  558.  * Finish off a filled-in header block and write it out.
  559.  * We also print the file name and/or full info if verbose is on.
  560.  */
  561. void
  562. finish_header(header)
  563.     register union record *header;
  564. {
  565.     register int    i, sum;
  566.     register char    *p;
  567.  
  568.     bcopy(CHKBLANKS, header->header.chksum, sizeof(header->header.chksum));
  569.  
  570.     sum = 0;
  571.     p = header->charptr;
  572.     for (i = sizeof(*header); --i >= 0; ) {
  573.         /*
  574.          * We can't use unsigned char here because of old compilers,
  575.          * e.g. V7.
  576.          */
  577.         sum += 0xFF & *p++;
  578.     }
  579.  
  580.     /*
  581.      * Fill in the checksum field.  It's formatted differently
  582.      * from the other fields:  it has [6] digits, a null, then a
  583.      * space -- rather than digits, a space, then a null.
  584.      * We use to_oct then write the null in over to_oct's space.
  585.      * The final space is already there, from checksumming, and
  586.      * to_oct doesn't modify it.
  587.      *
  588.      * This is a fast way to do:
  589.      * (void) sprintf(header->header.chksum, "%6o", sum);
  590.      */
  591.     to_oct((long) sum,    8,  header->header.chksum);
  592.     header->header.chksum[6] = '\0';    /* Zap the space */
  593.  
  594.     userec(header);
  595.  
  596.     if (f_verbose) {
  597.         /* These globals are parameters to print_header, sigh */
  598.         head = header;
  599.         /* hstat is already set up */
  600.         head_standard = f_standard;
  601.         print_header(stderr);
  602.     }
  603.  
  604.     return;
  605. }
  606.  
  607.  
  608. /*
  609.  * Quick and dirty octal conversion.
  610.  * Converts long "value" into a "digs"-digit field at "where",
  611.  * including a trailing space and room for a null.  "digs"==3 means
  612.  * 1 digit, a space, and room for a null.
  613.  *
  614.  * We assume the trailing null is already there and don't fill it in.
  615.  * This fact is used by start_header and finish_header, so don't change it!
  616.  *
  617.  * This should be equivalent to:
  618.  *    (void) sprintf(where, "%*lo ", digs-2, value);
  619.  * except that sprintf fills in the trailing null and we don't.
  620.  */
  621. void
  622. to_oct(value, digs, where)
  623.     register long    value;
  624.     register int    digs;
  625.     register char    *where;
  626. {
  627.     
  628.     --digs;                /* Trailing null slot is left alone */
  629.     where[--digs] = ' ';        /* Put in the space, though */
  630.  
  631.     /* Produce the digits -- at least one */
  632.     do {
  633.         where[--digs] = '0' + (char)(value & 7); /* one octal digit */
  634.         value >>= 3;
  635.     } while (digs > 0 && value != 0);
  636.  
  637.     /* Leading spaces, if necessary */
  638.     while (digs > 0)
  639.         where[--digs] = ' ';
  640.  
  641. }
  642.  
  643.  
  644. /*
  645.  * Write the EOT record(s).
  646.  * We actually zero at least one record, through the end of the block.
  647.  * Old tar writes garbage after two zeroed records -- and PDtar used to.
  648.  */
  649. write_eot()
  650. {
  651.     union record *p;
  652.     int bufsize;
  653.  
  654.     p = findrec();
  655.     bufsize = endofrecs()->charptr - p->charptr;
  656.     bzero(p->charptr, bufsize);
  657.     userec(p);
  658. }
  659.  
  660. #ifdef AMIGA
  661. /*
  662.  * 32-bit to 8 ascii chars as hex plus null term
  663.  */
  664. void
  665. to_hex(u_long val, char *p)
  666. {
  667.     int i, nibble;
  668.  
  669.     p += 8;            /* point to last char */
  670.     *p = '\0';            /* null term */
  671.     for (i = 0; i < 8; i++)
  672.     {
  673.     nibble = val & 0xf;
  674.     *--p = (nibble > 9) ? (nibble - 10) + 'a' : nibble + '0';
  675.     val >>= 4;
  676.     }
  677. }
  678. #endif
  679.